Part 33: ManxomeBromide - The Basics of BASIC
Randalor posted:
But I would love a "Here's what all this shit actually means" post in English. As dumbed down as much as possible without being condescending (well, unless it's humorous condescending. And with pictures. And Alice. Cravats)
ToxicFrog posted:
I've been programming for nearly 25 years now (15 of those professionally) and I can't read C=64 BASIC either.
I'm probably going to end up aiming too high and too low with this, but here's my attempt to give a 50,000 foot tour aimed at people who both have and have not coded in the modern era:
Tech Post: The Basics of BASIC
BASIC as a language has evolved significantly over the years, evolving from a kind of simple interpreted FORTRAN through Yet Another Language Vaguely Like Pascal into Yet Another Language Vaguely Like Java. It was invented at Dartmouth, but any BASIC that any of us here used was either directly written by Microsoft, was replaced by one directly written by Microsoft, or which was modeled directly on a Microsoft BASIC. There was a notion of a "standard BASIC" and every microcomputer implemented a system-specific variant of it that took better advantage of the system it was running on, and which usually omitted some features that were accepted as A Thing BASICs Were Supposed To Do, but turns out they never did.
The only concession C64 BASIC makes to the platform is a notion of, well, text control emojis. Those are the weird symbols we've been typing in to change the colors or move the cursor around the screen or clear the screen. Everything else, you're on your own. Fortunately, you don't need much more, because all of the C64's hardware is controllable via writing and reading values to known memory addresses, and BASIC turns out to be able to do that just fine. The concept of "device drivers", much less "hardware abstraction layer", won't be reaching personal computing for a long time to come.
Anyway, as a language, it bears almost no resemblance to any programming language in modern use, including the ones we still call Basic. It has a warm spot in many of our hearts, though, because it gave you the experience of turning on a computer, commanding it to work out problems for you, and then getting those answers back. The closest experience you can get to that nowadays is with a language like Python, but the most common way of getting that feeling from a computer seems to be Excel.
So, here's a rundown of the way the language works. Stuff in italics is where I draw direct comparisons to stuff modern programmers would be aware of. I'm simplifying this and ignoring some edge cases, which in some cases means I'm stating blatant lies. Fear not; they're not important blatant lies.
- Each line in a program has a line number, and the program is sorted in line number order. A line of BASIC code starts with a number, and then proceeds with a series of statements. You can have more than one statement per line; if you do, the lines are separated with colons. If you enter some statements without a line number, it runs it right away. Getting to use a full-screen editor is a major part of why things like C64List and petcat see use now.
- Data is stored in variables. Each variable has one or two letters in its name and then maybe a funny character that says what kind of data it holds. A$ holds a string. A holds a number. A% holds a number between -32768 and 32767 with no fractions, and you usually don't want to do this. Developers aren't being telegraphic when they name everything C4 or ZZ just to save space. They only have two characters to work with. As has come up, too, because spaces are optional, this is super dangerous because if you refer to a variable as STOAT that's actually S TO AT, not ST.
- You can also stick data into arrays, which let you use a number to pick which one you want. So, for instance, if you had an array for describing playing cards, maybe you'd have a Card Suit array for the names of the suits. Then maybe CS$(2) would be "DIAMONDS" and CS$(3) would be "SPADES". Arrays are secretly zero-indexed, but there is an extremely strong tradition in BASIC to pretend they are one-indexed, and the language encourages this.
- All variables spring into existence as needed, and can be accessed anywhere. There's a command called DIM (for "Dimension") that lets you set how big arrays are, but you don't have to use it; if you don't, the array will have ten elements. That's right, kids; every variable is global. BASIC has no notion of local variables, or, indeed, of functions or structs.
- DATA lines are a sort of separate startup-data file. If you hit a DATA line when running, you skip it. Bit if you looked at only the DATA lines, start to end, you'd have a sort of second file full of strings and numbers. There's a command called READ that takes the next value from that, in order. This is handy for setting stuff up, and about 90% of the "Please wait while I set stuff up" we're seeing is reading tons of DATA into the places they're supposed to actually be. BASIC has no notion object initializers, which would solve a decent fraction of this, but less than you'd think. More often than not DATA statements are binary dumps to be blitted into memory, not values to be fed into arrays.
- Statements do stuff. The big things you want to do are PRINT stuff out, POKE values into memory, assign values to variables with a statement like F=C*1.8+32, GET a character from the keyboard, READ a value from the DATA stream (usually to assign values to statements or to POKE them somewhere we want them), or GOTO some other line number. There is also a GOSUB command, which is like GOTO but it remembers where you were, and then there is a RETURN statement, that pops you back to where you were the last time you did a GOSUB. If you want to do stuff a bunch of times, you can enter a command like FOR I=1 to 10:(... stuff here ...):NEXT I and this will run the "stuff here" statements ten times, with the variable I starting at 1 and going up to 10. Disciplined use of GOSUB and RETURN, along with dedicated variables for parameters and return values, will get you some semblance of subroutines and functions. A lot of developers liked to organize code into blocks so that, say, lines 1000-2000 were reserved for one routine, 2000-3000 for another, and so on, and leave big gaps in their program numbering so that all GOSUB statements were to big round numbers. Others preferred crunching the numbers down. This caused about as much strife then as arguing about indentation style does now. FOR/NEXT is interesting because C and its descendants technically don't have it; a C or Java "for" loop is actually a rewritten "while".
- Some statements exist just organize other statements. The big ones here are IF, and ON. A statement like IF F<32 THEN PRINT "WOW, IT'S COLD" will, well, print out "Wow, it's cold" if F is less than 32. You can stick multiple statements after a THEN and all of them will run only if the condition was true. If the condition is false you skip straight to the next line in the program. ON is for when you'd need a ton of IF statements; ON K GOTO 30, 40, 50 will goto 30 if K is 1, 40 if it's 2, 50 if it's 3, and on to the next statement if it's not any of those. It's very common for IF statements to end up leading to THEN GOTO; this turns understanding or running a program into a sort of Choose Your Own Adventure. "Check the value of A. If it is less than 3, jump up and down say "HOORAY!", and then turn to page 70. Otherwise, go on to the next page." That's right; not only is everything global, there is no block structure whatsoever. With IF and GOTO you can implement while and repeat loops, which now guarantees that we're at least Turing-Complete. Other BASICs of the time included WHILE/WEND for real while statements, and they ultimately settled on a DO-LOOP syntax that quite frankly is cleaner than Pascal's or C's. ON is technically a computed GOTO but shrewd use of it is immensely powerful and can do things ranging from a common switch block to something like a virtual method call.
- BASIC has a bunch of math functions, and then similar things for strings. It's not a huge surprise that PRINT ATN(1)*4 will print out pi, but then you've also got things like LEFT$ and RIGHT$ for picking off the edges of strings, or MID$ for general substrings, or ASC for the character code of the first letter in a string. Note that the funny characters at the ends of functions match. For the C64 in particular, a super-important function is PEEK, which reads a value out of memory. Using PEEK correctly lets the hardware tell us stuff we want to know. Not much to add here, really, though I will note that because of the way string functions work, BASIC must be a garbage-collected language, and it is. Garbage collection turns out to be way easier when you have no notion of pointers or locals and every variable is global and lives forever.
This isn't enough to actually write any BASIC programs of any complexity, but there's no shortage of books teaching that if you actually wanted to learn it. (Just learn Python instead, seriously.) Hopefully though this is enough to be able to work the general structure behind what otherwise looks like a GIANT WALL OF TEXT.
Culka posted:
Related to all the programming, commodore 64 still has a somewhat active demoscene community around it developing new demos. I say developing, but actually mean making the hardware do things that it was never meant to do. For example:
Making games run well using clever tricks is one thing, but this is pure wizardry.
The best part of this is that it's totally casual about throwing in things like scrolling a single line diagonally two directions at once, which looks pretty nice but doesn't call attention to itself unless you've tried to do scrolling work on the C64 yourself, at which point it becomes purest I thought I had worked out the trick there when I saw it, but on a rewatch, nope, what I thought they were doing totally wouldn't work.